/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package motiveai.factors;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import motiveai.components.BehaviourEntity;
/**
 *
 * @author oxplay
 */
public class Environment {
    
    private final static Logger logger = Logger.getLogger(Environment.class.getName());
    private EnvironmentDefinition environmentDefinition;
    private EnvironmentSharedData environmentSharedData;
    private Map<String, Object> factors = new HashMap<String, Object>();

    public Map<String, Object> getFactors() {
        return factors;
    }

    public EnvironmentDefinition getEnvironmentDefinition() {
        return environmentDefinition;
    }

    public EnvironmentSharedData getEnvironmentSharedData() {
        return environmentSharedData;
    }

    protected void setEnvironmentDefinition(EnvironmentDefinition environmentDefinition) {
        this.environmentDefinition = environmentDefinition;
    }

    public boolean getBooleanFactor(String name) {
        return (Boolean) factors.get(name);
    }

    public int getIntegerFactor(String name) {
        return (Integer) factors.get(name);
    }

    /*
     * Set factor for boolean
     */
    public void setBooleanFactor(String name, boolean value) {
        factors.put(name, value);
    }

    /*
     * Set factor for integer
     */
    public void setIntegerFactor(String name, int value) {
        factors.put(name, value);
    }
    
    public void updateData() {
       final int prime = 31;
       int hashCode = 1;
        float performance = 0;
        for (Iterator<String> it = factors.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            Object factor = factors.get(name);
            if (factor instanceof Boolean) {
                Boolean factorValue = (Boolean) factor;
                FactorBoolean factorDefinition = environmentDefinition.getBooleanFactorDefinition(name);
                hashCode = prime * hashCode + (factorValue ? 1231 : 1237);
                if (factorValue == factorDefinition.getValueNeeded()) {
                    performance += (float) factorDefinition.getPerformance();
                }
            } else {
                Integer factorValue = (Integer) factor;
                FactorInteger factorDefinition = environmentDefinition.getIntegerFactorDefinition(name);
                hashCode = prime * hashCode + factorValue;
                performance += factorDefinition.getScaledPerformance(factorValue);
            }
        }
        environmentSharedData = environmentDefinition.getEnvironmentSharedData(hashCode);
        if(environmentSharedData == null){
            environmentSharedData = new EnvironmentSharedData(hashCode, performance);
            environmentDefinition.putEnvironmentSharedData(environmentSharedData);
        }
    }

    /*
     * this method contain hashCode that make sets of identical Environment conditions
     * the more diverse environments, the more solutions it seek.
     * it should be based only on booleans or integers(with limited scope)
     */
    public int getCalculatedHashCode() {
        return environmentSharedData.getHashCode();
    }

    /*
     * Return value 0-1 float that mean performance of Environment
     */
    public float getPerformance() {
        return environmentSharedData.getPerformance();
    }

    /*
     * Return List of Behaviours made in that conditions of Environment
     */
    public Map<String, BehaviourEntity> getBehaviourMemory() {
        return environmentSharedData.getBehaviourMemory();
    }

    /*
     * Adds done Behaviour into memory.
     * it is remembered in Environment and Learn Central Unit takes it into account.
     */
    public void addBehaviourMemory(BehaviourEntity behaviour) {
        environmentSharedData.addBehaviourMemory(behaviour);
    }

    /*
     * clone Environment with its data.
     */
    public Environment cloneEnvironment() {
        Environment env = new Environment();
        env.environmentDefinition = environmentDefinition;
        env.environmentSharedData = environmentSharedData;
        env.factors.putAll(factors);
        return env;
    }

    /*
     * Use system output to print Environment Data.
     */
    public void printEnvironment() {
        System.out.println("printEnvironment() env performance: " + getPerformance());
        for (Iterator<String> it = factors.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            Object factor = factors.get(name);
            if (factor instanceof Boolean) {
                Boolean factorBoolean = (Boolean) factor;
                System.out.println("Env " + name + " value: " + factorBoolean);
            } else {
                Integer factorInteger = (Integer) factor;
                System.out.println("Env " + name + " value: " + factorInteger);
            }
        }
    }

}
